#include <iostream>
#include <cstdio>
#include <list>

// a redefinir si usage VS CC
// __LINE__, __FILE__ & __PRETTY_FUNCTION__ => macros GCC
#define EXC_LINE     __LINE__
#define EXC_FILE     __FILE__
#define EXC_FUNC     __PRETTY_FUNCTION__

// MSG = const char* ou std::string
#define EXC_THROW(MSG)                                              \
    do {                                                            \
        throw Exc(MSG, EXC_FILE, EXC_LINE, EXC_FUNC);               \
    } while (0)


#define EXC_RETHROW_BEGIN()                                         \
    try


#define EXC_RETHROW_END()                                           \
    catch(Exc& e) {                                                 \
        e.push(EXC_FILE, EXC_LINE, EXC_FUNC);                       \
        throw e;                                                    \
    }

// COND => si cette condition n'est pas remplie
// MSG  => ce msg est envoye
#define EXC_THROW_ON_FAILED(COND, MSG)                              \
    do {                                                            \
        if (!(COND))                                                \
            EXC_THROW(MSG);                                         \
    } while(0)


class Exc
{
    public:
        Exc(const std::string& inMsg, const std::string& inFile,
            unsigned int inLine, const std::string& inFunc)
            : exMsg(inMsg)
        {   
            push(inFile, inLine, inFunc);
        }
        
        void    push(const std::string& inFile, 
                unsigned int inLine, const std::string& inFunc)
        {
            char        buffer[0x1000];
            
            sprintf(buffer, "%s:%u\t%s", inFile.c_str(), inLine, inFunc.c_str());
            exStack.push_back(std::string(buffer));
        }
        
        void    printMsg()
        {
            std::cerr << "EXCEPTION \t>> " << exMsg << std::endl;
        }
        
        void    printStackTrace()
        {
            std::list<std::string>::const_iterator it;
            
            for (it = exStack.begin() ; it != exStack.end() ; it++)
                std::cerr << *it << std::endl;
        }
        
    protected:
        std::list<std::string> exStack;
        std::string            exMsg;
};
